/**
 ******************************************************************************
 * @file    crc.c
 * @author  hyseim software Team
 * @date    13-Mar-2024
 * @brief   This file provides all the tmp functions.
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2020 Hyseim. Co., Ltd.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "crc.h"

/** @addtogroup IM110GW_Driver
 * @{
 */

/** @defgroup CRC
 * @brief CRC driver modules
 * @{
 */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/** @defgroup CRC_Private_Functions
  * @{
  */

/**
 * @brief  Set the initial xor value for CRC.
 * @param  bitwidth: CRC bit width.
 * @param  totr: CRC totr type.
 * @param  xor_value: CRC initial xor value.
 * @return None
 */
void CRC_SetXor(uint32_t bitwidth, uint32_t totr, uint32_t xor_value)
{
    if ((totr == CRC_ReadTranspose_BitsAndBytes) || (totr == CRC_ReadTranspose_Bytes))
    {
        if (bitwidth == CRC_BitWidth_8b)
        {
            CRC->OXOR = xor_value << 24;
        }
        else if (bitwidth == CRC_BitWidth_16b)
        {
            CRC->OXOR = xor_value << 16;
        }
        else if (bitwidth == CRC_BitWidth_32b)
        {
            CRC->OXOR = xor_value;
        }
    }
    else 
    {
        CRC->OXOR = xor_value;
    }
}

/**
 * @brief  Initializes the CRC module.
 * @param  CRC_InitStruct: pointer to a CRC_Init_t structure
 *         that contains the configuration information for the specified 
 *         CRC peripheral.
 * @return None
 */
void CRC_Init(CRC_Init_t *CRC_InitStruct)
{
    CRC_SetXor(CRC_InitStruct->CRC_BitWidth, CRC_InitStruct->CRC_TotrMode, CRC_InitStruct->CRC_Oxor);

    CRC->GPOLY = CRC_InitStruct->CRC_Gpoly;

    CRC->SEED = CRC_InitStruct->CRC_Seed;

    CRC->CTRL = CRC_CTRL_CRC_EN | CRC_InitStruct->CRC_BitWidth | CRC_InitStruct->CRC_OxorMode | 
                CRC_InitStruct->CRC_TotrMode | CRC_InitStruct->CRC_TotMode;
}

/**
 * @brief  Fills each CRC_StructInit member with its default value.
 * @param  CRC_StructInit: pointer to a CRC_Init_t structure which
 *         will be initialized.
 * @return None
 */
void CRC_StructInit(CRC_Init_t* CRC_StructInit)
{
    /* CRC_InitStruct members default value */
    CRC_StructInit->CRC_Gpoly = 0x1021;
    CRC_StructInit->CRC_Seed = 0xFFFFFFFF;
    CRC_StructInit->CRC_Oxor = 0x0;
    CRC_StructInit->CRC_BitWidth = CRC_BitWidth_16b;
    CRC_StructInit->CRC_OxorMode = CRC_Xor_Enable;
    CRC_StructInit->CRC_TotMode = CRC_WriteTranspose_None;
    CRC_StructInit->CRC_TotrMode = CRC_ReadTranspose_None;
}

/**
 * @brief  Gets the CRC bit width.
 * @return CRC bit width type
 */
uint32_t CRC_GetBitWidth(void)
{
    uint32_t type;
    uint32_t temp = (CRC->CTRL & CRC_CTRL_TCRC_MASK) >> 24;

    switch (temp)
    {
        case 0U:
            type = CRC_BitWidth_16b;
            break;
        case 1U:
            type = CRC_BitWidth_32b;
            break;
        default:
            type = CRC_BitWidth_8b;
            break;
    }

    return type;
}

/**
 * @brief  Gets the CRC transpose type for writes.
 * @return CRC input transpose type for writes
 */
uint32_t CRC_GetWriteTranspose(void)
{
    uint32_t type;
    uint32_t temp = (CRC->CTRL & CRC_CTRL_TOT_TRANSPOSE_MASK) >> 30;

    switch (temp)
    {
        case 1U:
            type = CRC_WriteTranspose_Bits;
            break;
        case 2U:
            type = CRC_WriteTranspose_BitsAndBytes;
            break;
        case 3U:
            type = CRC_WriteTranspose_Bytes;
            break;
        default:
            type = CRC_WriteTranspose_None;
            break;
    }

    return type;
}

/**
 * @brief  Gets the CRC transpose type for reads.
 * @return CRC output transpose type
 */
uint32_t CRC_GetReadTranspose(void)
{
    uint32_t type;
    uint32_t temp = (CRC->CTRL & CRC_CTRL_TOTR_TRANSPOSE_MASK) >> 28;

    switch (temp)
    {
        case 1U:
            type = CRC_ReadTranspose_Bits;
            break;
        case 2U:
            type = CRC_ReadTranspose_BitsAndBytes;
            break;
        case 3U:
            type = CRC_ReadTranspose_Bytes;
            break;
        default:
            type = CRC_ReadTranspose_None;
            break;
    }

    return type;
}

/**
 * @brief  Computes the 8-bit CRC of a given buffer of byte(8-bit).
 * @param  ptr_data: Pointer to the buffer containing the data to be computed
 * @param  data_len: Length of the buffer to be computed
 * @return Result of 8-bit CRC calculation
 */
uint8_t CRC8_Calculate(const uint8_t *ptr_data, uint32_t data_len)
{
    unsigned char crc_result;
    unsigned int crc_mode;

    crc_mode = CRC_GetWriteTranspose();
    
    while (data_len--)
    {   
        if ((crc_mode == CRC_WriteTranspose_BitsAndBytes) || (crc_mode == CRC_WriteTranspose_Bytes)){
           CRC->DATA = *ptr_data++ << 24;
        }
        else {
            CRC->DATA = *ptr_data++;
        }
    }

    crc_mode = CRC_GetReadTranspose();

    if ((crc_mode == CRC_ReadTranspose_BitsAndBytes) || (crc_mode == CRC_ReadTranspose_Bytes)){
        crc_result = CRC->DATA >> 24;
    }
    else {
        crc_result = CRC->DATA;
    }
    return crc_result;
}

/**
 * @brief  Computes the 16-bit CRC of a given buffer of byte(16-bit).
 * @param  ptr_data: Pointer to the buffer containing the data to be computed
 * @param  data_len: Length of the buffer to be computed
 * @return Result of 16-bit CRC calculation
 */
uint16_t CRC16_Calculate(const uint16_t *ptr_data, uint32_t data_len)
{
    unsigned short crc_result = 0;
    unsigned int crc_mode;

    crc_mode = CRC_GetWriteTranspose();

    while (data_len--)
    {   
        if ((crc_mode == CRC_WriteTranspose_BitsAndBytes) || (crc_mode == CRC_WriteTranspose_Bytes)){
           CRC->DATA = *ptr_data++ << 16;
        }
        else {
           CRC->DATA = *ptr_data++;
        }
    }

    crc_mode = CRC_GetReadTranspose();
    if ((crc_mode == CRC_ReadTranspose_BitsAndBytes) || (crc_mode == CRC_ReadTranspose_Bytes)){
        crc_result = CRC->DATA >> 16;
    }
    else {
        crc_result = CRC->DATA;
    }
    return crc_result;
}

/**
 * @brief  Computes the 32-bit CRC of a given buffer of byte(32-bit).
 * @param  ptr_data: Pointer to the buffer containing the data to be computed
 * @param  data_len: Length of the buffer to be computed
 * @return Result of 32-bit CRC calculation
 */
uint32_t CRC32_Calculate(const uint32_t *ptr_data, uint32_t data_len)
{
    while (data_len--)
    {
       CRC->DATA = *ptr_data++;
    }

    return CRC->DATA;
}

/**
  * @}
  */

/**
 * @}
 */

/**
 * @}
 */
